package com.huilian.iotbox.admin.service.impl;

import com.huilian.iotbox.admin.activity.service.ActivityService;
import com.huilian.iotbox.admin.dao.StatsDeviceDao;
import com.huilian.iotbox.admin.service.*;
import com.huilian.iotbox.data.dto.*;
import com.huilian.iotbox.data.enums.*;
import com.huilian.iotbox.data.po.StatsDevice;
import com.huilian.iotbox.data.service.ErrorLogCommonService;
import com.huilian.iotbox.data.service.StatsDeviceCommonService;
import com.huilian.iotbox.data.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 龙 路 飞
 * @CreateDate: 2021-09-18 16:19
 * @Description:
 */
@Service
@Slf4j
public class StatsDeviceServiceImpl implements StatsDeviceService {

    @Autowired
    private OrderService orderService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private StatsDeviceDao statsDeviceDao;
    @Autowired
    private ActivityService activityService;
    @Autowired
    private ErrorLogCommonService errorLogCommonService;
    @Autowired
    private StatsDeviceCommonService statsDeviceCommonService;

    /**
     * 生成key
     *
     * @param merchantStoreId
     * @param deviceNo
     * @param deviceTypeId
     * @return
     */
    private String generateKey(int merchantStoreId, String deviceNo, int deviceTypeId, Integer hierarchy, Integer freightLane) {
        return new StringBuffer(String.valueOf(merchantStoreId))
                .append("_").append(deviceNo)
                .append("_").append(deviceTypeId)
                .append("_").append(StringUtils.isEmpty(hierarchy) ? 0 : hierarchy)
                .append("_").append(StringUtils.isEmpty(freightLane) ? 0 : freightLane)
                .toString();
    }

    @Override
    public void statsDayDeviceJob(String startTime, String endTime, String yesterday) {

        final List<DeviceVo> deviceVoList = deviceService.findDeviceAll(null);
        final Map<String, DeviceVo> deviceVoMap = deviceVoList.stream().collect(Collectors.toMap(DeviceVo::getDeviceNo, a -> a, (k1, k2) -> k1));

        Map<String, StatsDevice> statsDeviceMap = new HashMap<>();

        final StatsDevice statsDeviceTemp = new StatsDevice();
        statsDeviceTemp.setType(StatisticsTypeEnum.DAY.getCode());
        statsDeviceTemp.setDateStr(yesterday);

        //普通订单
        OrderDto orderDto = new OrderDto();
        orderDto.setStartTime(startTime);
        orderDto.setEndTime(endTime);
        // o.merchantStoreId, o.deviceNo, o.deviceTypeId, oi.hierarchy, oi.freightLane
        List<OrderVo> orderVoList = orderService.findSuccessTotalAmountList(orderDto);
        for (OrderVo orderVo : orderVoList) {
            log.info("orderVo.getDeviceNo():{}", orderVo.getDeviceNo());
            final DeviceVo deviceVo = deviceVoMap.get(orderVo.getDeviceNo());
            StatsDevice statsDevice = new StatsDevice();
            statsDevice.setType(statsDeviceTemp.getType());
            statsDevice.setDateStr(statsDeviceTemp.getDateStr());

            statsDevice.setMchStoreId(orderVo.getMerchantStoreId());
            statsDevice.setDeviceNo(orderVo.getDeviceNo());
            statsDevice.setDeviceTypeId(orderVo.getDeviceTypeId());
            statsDevice.setHierarchy(orderVo.getHierarchy());
            statsDevice.setFreightLane(orderVo.getFreightLane());

            statsDevice.setTurnover(orderVo.getTurnover());
            statsDevice.setTurnoverOnLine(orderVo.getTurnoverOnLine());
            statsDevice.setTurnoverOffline(orderVo.getTurnoverOffline());
            statsDevice.setTurnoverDouYin(orderVo.getTurnoverDouYin());
            statsDevice.setTurnoverMeiTuan(orderVo.getTurnoverMeiTuan());
            statsDevice.setConsumeCount(0);
            statsDevice.setGiftConsume(0);
            statsDevice.setSelfServiceTerminalCash(orderVo.getSelfServiceTerminalCash());

            // 统计兑币机每个面额收了多少次
            if (
                    !StringUtils.isEmpty(deviceVo.getDeviceTypeId())
                            && (
                            DeviceTypeEnum.SUPER_MONEY_CHANGER.getCode().compareTo(deviceVo.getDeviceTypeId()) == 0
                                    || DeviceTypeEnum.CONVERTIBLE_CURRENCY_MACHINE.getCode().compareTo(deviceVo.getDeviceTypeId()) == 0
                    )
            ) {
                this.statsDeviceDenomination(deviceVo, startTime, endTime, statsDevice);
            }

            statsDeviceMap.put(
                    this.generateKey(orderVo.getMerchantStoreId(), orderVo.getDeviceNo(), orderVo.getDeviceTypeId(), orderVo.getHierarchy(), orderVo.getFreightLane()),
                    statsDevice
            );
        }

        ActivityOrderDto activityOrderDto = new ActivityOrderDto();
        activityOrderDto.setStartTime(startTime);
        activityOrderDto.setEndTime(endTime);
        // ao.merchantStoreId, d.deviceNo, d.deviceTypeId
        final List<ActivityVo> activityOrderVoList = activityService.findSuccessTotalAmountByDeviceList(activityOrderDto);
        if (!ObjectUtils.isEmpty(activityOrderVoList) && activityOrderVoList.size() > 0) {
            for (ActivityVo activityVo : activityOrderVoList) {
                final String key = this.generateKey(activityVo.getMerchantStoreId(), activityVo.getDeviceNo(), activityVo.getDeviceTypeId(), null, null);
                StatsDevice statsDevice = statsDeviceMap.get(key);
                if (StringUtils.isEmpty(statsDevice)) {
                    statsDevice = new StatsDevice();
                    statsDevice.setType(statsDeviceTemp.getType());
                    statsDevice.setDateStr(statsDeviceTemp.getDateStr());

                    statsDevice.setMchStoreId(activityVo.getMerchantStoreId());
                    statsDevice.setDeviceNo(activityVo.getDeviceNo());
                    statsDevice.setDeviceTypeId(activityVo.getDeviceTypeId());
                }

                log.info("活动套餐设备：{}", activityVo.getDeviceNo());
                log.info("秒杀活动收款金额：{}", activityVo.getSeckillMoney());
                log.info("拼团活动收款金额：{}", activityVo.getGroupBookingMoney());
                log.info("消费红包活动收款金额：{}", activityVo.getConsumptionOfRedEnvelopesMoney());
                log.info("会员储值活动收款金额：{}", activityVo.getMemberOfTheStoredValueMoney());
                log.info("活动核销金额：秒杀活动核销金额+拼团活动核销金额：{}", activityVo.getActivityCancelledMoney());
                log.info("活动活动未核销金额：秒杀活动未核销金额+拼团活动未核销金额套餐设别：{}", activityVo.getActivityUnwrittenMoney());

                statsDevice.setDeviceNo(activityVo.getDeviceNo());
                statsDevice.setTurnover((StringUtils.isEmpty(statsDevice.getTurnover()) ? BigDecimal.ZERO : statsDevice.getTurnover()).add(activityVo.getTurnover()));
                statsDevice.setSeckillMoney(activityVo.getSeckillMoney());
                statsDevice.setGroupBookingMoney(activityVo.getGroupBookingMoney());
                statsDevice.setConsumptionOfRedEnvelopesMoney(activityVo.getConsumptionOfRedEnvelopesMoney());
                statsDevice.setMemberOfTheStoredValueMoney(activityVo.getMemberOfTheStoredValueMoney());
                statsDevice.setActivityCancelledMoney(activityVo.getActivityCancelledMoney());
                statsDevice.setActivityUnwrittenMoney(activityVo.getActivityUnwrittenMoney());
                statsDeviceMap.put(key, statsDevice);
            }
        }


        ConsumeRecordDto consumeRecordDto = new ConsumeRecordDto();
        consumeRecordDto.setStatus(ConsumeRecordStatusEnum.SUCCESS.getCode());
        consumeRecordDto.setStartTime(startTime);
        consumeRecordDto.setEndTime(endTime);
        consumeRecordDto.setConsumeRecordTypeIdArray(
                new int[]{
                        ConsumeRecordTypeEnum.COIN_MACHINE.getCode(),
                        ConsumeRecordTypeEnum.COIN_MACHINE_FETCH_COIN.getCode(),
                        ConsumeRecordTypeEnum.COIN_MACHINE_DOUYIN_VERIFY.getCode(),
                        ConsumeRecordTypeEnum.COIN_MACHINE_MEITUAN_VERIFY.getCode(),
                        ConsumeRecordTypeEnum.COUNT_OUT_COIN.getCode(),
                        ConsumeRecordTypeEnum.WEIXIN_SECKILL_VERIFY.getCode(),
                        ConsumeRecordTypeEnum.WEIXIN_GROUP_BUYING_VERIFY.getCode(),
                        ConsumeRecordTypeEnum.WEIXIN_VOUCHER_VERIFY.getCode(),
                        ConsumeRecordTypeEnum.CONSUME.getCode()
                }
        );

        for (StatsDevice value : statsDeviceMap.values()) {
            try {
                if (StringUtils.isEmpty(value.getTurnover()) || value.getTurnover().compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                final DeviceVo deviceVo = deviceVoMap.get(value.getDeviceNo());
                DeviceVo vo = new DeviceVo();
                vo.setId(deviceVo.getId());
                if (StringUtils.isEmpty(deviceVo.getTotalTransactionAmount())) {
                    vo.setTotalTransactionAmount(value.getTurnover());
                } else {
                    vo.setTotalTransactionAmount(deviceVo.getTotalTransactionAmount().add(value.getTurnover()));
                }
                deviceService.updateDeviceTotalTransactionAmount(vo);
            } catch (Exception e) {
                e.printStackTrace();
                errorLogCommonService.writerInfoException("统计设备返佣总金额出错", value.getDeviceNo(), e);
            }
        }


        /**
         * 分片批量插入（批量数据过大）-begin
         */
        List<StatsDevice> collect = statsDeviceMap.values().stream().collect(Collectors.toList());
        // 每批100条数据
        int size = 100;

        List<List<StatsDevice>> fragmentList = new ArrayList<>();
        int maxLen = collect.size() % size == 0 ? collect.size() / size : collect.size() / size + 1;
        for (int i = 1; i <= maxLen; i++) {
            if (i == maxLen) {
                List<StatsDevice> statsDevice = collect.subList((i - 1) * size, collect.size());
                fragmentList.add(statsDevice);
            } else {
                List<StatsDevice> statsDevice = collect.subList((i - 1) * size, i * size);
                fragmentList.add(statsDevice);
            }
        }

        for (List<StatsDevice> statsDevice : fragmentList) {
            statsDeviceDao.batchInsert(statsDevice);
        }
        /**
         * 分片批量插入（批量数据过大）-end
         */

        log.info("statsDeviceMap:{}", statsDeviceMap.size());
    }

    /**
     * 兑币机计算面额命中次数
     *
     * @param deviceVo
     * @param startTime
     * @param endTime
     * @param statsDevice
     */
    private void statsDeviceDenomination(DeviceVo deviceVo, String startTime, String endTime, StatsDevice statsDevice) {
        Integer[] deviceTypeIdArray = new Integer[]{
                DeviceTypeEnum.SUPER_MONEY_CHANGER.getCode(),
                DeviceTypeEnum.CONVERTIBLE_CURRENCY_MACHINE.getCode()
        };
        String[] channelTypeArray = new String[]{
                ChannelTypeEnum.BILL_MACHINE.getCode(),
                ChannelTypeEnum.COIN_BOX.getCode()
        };
        Integer[] orderStatusArray = new Integer[]{
                OrderStatusEnum.SUCCESS.getCode(),
                OrderStatusEnum.PART_REFUND.getCode(),
                OrderStatusEnum.FULL_FERUND.getCode(),
                OrderStatusEnum.REFUNDING.getCode(),
        };


        OrderDto orderDenomination = new OrderDto();
        orderDenomination.setDeviceNo(deviceVo.getDeviceNo());
        orderDenomination.setStartTime(startTime);
        orderDenomination.setEndTime(endTime);
        orderDenomination.setMchType(MchTypeEnum.CASH_RECEIPTS.getCode());
        orderDenomination.setDeviceTypeIdArray(deviceTypeIdArray);
        orderDenomination.setChannelTypeArray(channelTypeArray);
        orderDenomination.setOrderStatusArray(orderStatusArray);
        List<OrderVo> orderVoList = orderService.findDenominationCountByDeviceNo(orderDenomination);

        statsDevice.setOneYuanDenomination(0);
        statsDevice.setFiveYuanDenomination(0);
        statsDevice.setTenYuanDenomination(0);
        statsDevice.setTwentyYuanDenomination(0);
        statsDevice.setFiftyYuanDenomination(0);
        statsDevice.setOneHundredYuanDenomination(0);

        if (orderVoList.size() > 0) {
            statsDeviceCommonService.statsDeviceDenomination(orderVoList, statsDevice);
        }
    }

    @Override
    public void statsMonthDeviceJob(String startDateStr, String endDateStr, String previousMonth) {
        List<StatsDevice> statsDeviceList = statsDeviceDao.statsDeviceMonth(startDateStr, endDateStr);
        // 获取上月日期 格式 yyyy-MM
        for (StatsDevice statsDevice : statsDeviceList) {
            statsDevice.setDateStr(previousMonth);
            statsDevice.setType(StatisticsTypeEnum.MONTH.getCode());
        }


        /**
         * 分片批量插入（批量数据过大）-begin
         */
        // 每批100条数据
        int size = 100;

        List<List<StatsDevice>> fragmentList = new ArrayList<>();
        int maxLen = statsDeviceList.size() % size == 0 ? statsDeviceList.size() / size : statsDeviceList.size() / size + 1;
        for (int i = 1; i <= maxLen; i++) {
            if (i == maxLen) {
                List<StatsDevice> statsDevice = statsDeviceList.subList((i - 1) * size, statsDeviceList.size());
                fragmentList.add(statsDevice);
            } else {
                List<StatsDevice> statsDevice = statsDeviceList.subList((i - 1) * size, i * size);
                fragmentList.add(statsDevice);
            }
        }

        for (List<StatsDevice> statsDevice : fragmentList) {
            log.info("批量插入数据：{}", statsDevice.size());
            statsDeviceDao.batchInsert(statsDevice);
        }
    }
}
